package com.person.jiaiplan.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.person.jiaiplan.assembler.SummaryReportAssembler;
import com.person.jiaiplan.contant.ConstGroupConstant;
import com.person.jiaiplan.contant.PlanAchievementEnum;
import com.person.jiaiplan.pojo.dto.SummaryReportReqDTO;
import com.person.jiaiplan.pojo.dto.SummaryReportResDTO;
import com.person.jiaiplan.pojo.dto.summary.*;
import com.person.jiaiplan.pojo.entity.Clocklogs;
import com.person.jiaiplan.pojo.entity.ScheduleLogs;
import com.person.jiaiplan.pojo.entity.SchedulePlanLogs;
import com.person.jiaiplan.service.ClocklogsService;
import com.person.jiaiplan.service.ScheduleLogsService;
import com.person.jiaiplan.service.SchedulePlanLogsService;
import com.person.jiaiplan.service.SummaryReportService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.DecimalFormat;
import java.util.*;

@Slf4j
@Service
public class SummaryReportServiceImpl implements SummaryReportService {

    @Autowired
    private ScheduleLogsService scheduleLogsService;

    @Autowired
    private ClocklogsService clocklogsService;

    @Autowired
    private SchedulePlanLogsService schedulePlanLogsService;

    @Override

    public IPage<SummaryReportResDTO> query(SummaryReportReqDTO reqDTO) {
        // 创建分页对象
        IPage<ScheduleLogs> page = new Page<>(reqDTO.getPageNum(), reqDTO.getPageSize());
        QueryWrapper<ScheduleLogs> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("operator_type", Integer.valueOf(reqDTO.getOperatorType()));
        if (reqDTO.getModel() != "" && reqDTO.getModel() != null) {
            queryWrapper.like("model", reqDTO.getModel());
        }
        if (reqDTO.getContent() != "" && reqDTO.getContent() != null) {
            queryWrapper.like("content", reqDTO.getContent());
        }

        page = scheduleLogsService.getBaseMapper().selectPage(page, queryWrapper);

        List<SummaryReportResDTO> summaryReportResDTOList = SummaryReportAssembler.INSTANCE.toSummaryReportResDTO(page.getRecords());
        // 检查周期配置
        summaryReportResDTOList = checkPlanCycle(summaryReportResDTOList, reqDTO.getStartTime(), reqDTO.getEndTime());

        // 插入打卡数据
        summaryReportResDTOList = queryClockIn(summaryReportResDTOList,reqDTO);

        CollectionUtil.sort(summaryReportResDTOList, Comparator.comparing(SummaryReportResDTO::getOperatorType).thenComparing(SummaryReportResDTO::getPlanStatus));

        IPage<SummaryReportResDTO> summaryReportResDTOIPage = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
        // summaryReportResDTOList 按照打卡状态 ，时间 进行排序

        summaryReportResDTOIPage.setRecords(summaryReportResDTOList);

        return summaryReportResDTOIPage;
    }


    /**
     * 检查周期配置筛选
     *
     * @param summaryReportResDTOList
     * @return
     */
    private List<SummaryReportResDTO> checkPlanCycle(List<SummaryReportResDTO> summaryReportResDTOList, String queryStartTime, String queryEndTime) {
        List<SummaryReportResDTO> addList = new LinkedList<>();

        // 根据周期去筛选数据 , 没有周期的数据不需要去查询打卡数据 ，也不展示在周计划中

        summaryReportResDTOList.stream().forEach(vo -> {
                    String scheduleId = vo.getId();
                    SchedulePlanLogs schedulePlanLogs = schedulePlanLogsService.getOne(Wrappers.lambdaQuery(SchedulePlanLogs.class).eq(SchedulePlanLogs::getScheduleId, scheduleId));
                    if (schedulePlanLogs != null) {
                        Date planStartTime = schedulePlanLogs.getPlanStartTime();
                        Date planEndTime = schedulePlanLogs.getPlanFinishTime();
                        Date startTime = DateUtil.beginOfDay(DateUtil.parse(queryStartTime));
                        Date endTime = DateUtil.endOfDay(DateUtil.parse(queryEndTime));

                        // 计划开始时间 < 查询结束
                        if (planStartTime.getTime() < endTime.getTime()) {
                            // 计划结束时间 > 查询开始
                            if (planEndTime.getTime() > startTime.getTime()) {
                                vo.setPlanStartTime(DateUtil.format(schedulePlanLogs.getPlanStartTime(), "yyyy-MM-dd"));
                                vo.setPlanEndTime(DateUtil.format(schedulePlanLogs.getPlanFinishTime(), "yyyy-MM-dd"));
                                addList.add(vo);
                            }
                        }
                    } else {
                        // 没有周期的数据，则根据 startTime 和 endTime 进行筛选 ,处理未进行周期配置的或者是补卡的数据
                        Date startTime = DateUtil.beginOfDay(DateUtil.parse(queryStartTime));
                        Date endTime = DateUtil.endOfDay(DateUtil.parse(queryEndTime));
                        Date createTime = vo.getCreateTime();
                        if (createTime.getTime() >= startTime.getTime() && createTime.getTime() <= endTime.getTime()) {
                            addList.add(vo);
                        }

                    }
                }

        );
        return addList;
    }

    @Override
    public List<WeeklySummaryResDTO> getWeeklySummary(WeeklySummaryReqDTO reqDTO) {

        // 如果没有传入时间，就默认查询本周的
        if (StrUtil.isBlank(reqDTO.getStartTime()) || StrUtil.isBlank(reqDTO.getEndTime())) {
            reqDTO.setStartTime(DateUtil.format(DateUtil.beginOfWeek(DateUtil.date()), "yyyy-MM-dd"));
            reqDTO.setEndTime(DateUtil.format(DateUtil.endOfWeek(DateUtil.date()), "yyyy-MM-dd"));
        }

        QueryWrapper<ScheduleLogs> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("operator_type", Integer.valueOf(reqDTO.getOperatorType()));
        if (reqDTO.getModel() != "" && reqDTO.getModel() != null) {
            queryWrapper.like("model", reqDTO.getModel());
        }
        if (reqDTO.getContent() != "" && reqDTO.getContent() != null) {
            queryWrapper.like("content", reqDTO.getContent());
        }

        List<ScheduleLogs> scheduleLogsList = scheduleLogsService.getBaseMapper().selectList(queryWrapper);
        if (scheduleLogsList == null || scheduleLogsList.size() == 0) {
            return new ArrayList<>();
        }
        List<SummaryReportResDTO> summaryReportResDTOList = SummaryReportAssembler.INSTANCE.toSummaryReportResDTO(scheduleLogsList);
        // 检查周期配置
        summaryReportResDTOList = checkPlanCycle(summaryReportResDTOList, reqDTO.getStartTime(), reqDTO.getEndTime());

        return generateWeeklySummary(summaryReportResDTOList, reqDTO);
    }

    @Override
    public List<AnnualSummaryResDTO> getAnnualSummary(AnnualSummaryReqDTO reqDTO) {
        QueryWrapper<ScheduleLogs> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("operator_type", Integer.valueOf(reqDTO.getOperatorType()));
        if (reqDTO.getModel() != "" && reqDTO.getModel() != null) {
            queryWrapper.like("model", reqDTO.getModel());
        }
        if (reqDTO.getContent() != "" && reqDTO.getContent() != null) {
            queryWrapper.like("content", reqDTO.getContent());
        }
        if (StrUtil.isNotBlank(reqDTO.getStartTime()) && StrUtil.isNotBlank(reqDTO.getEndTime())) {
            queryWrapper.between("create_time", DateUtil.beginOfDay(DateUtil.parseDate(reqDTO.getStartTime())), DateUtil.endOfDay(DateUtil.parseDate(reqDTO.getEndTime())));
        }
        List<ScheduleLogs> scheduleLogsList = scheduleLogsService.getBaseMapper().selectList(queryWrapper);
        if (scheduleLogsList == null || scheduleLogsList.size() == 0) {
            return new ArrayList<>();
        }
        List<AnnualSummaryResDTO> annualSummaryResDTOList = generateAnnualSummary(scheduleLogsList,reqDTO);
        // 按照计划创建时间排序
        CollectionUtil.sort(annualSummaryResDTOList, Comparator.comparing(AnnualSummaryResDTO::getCreateTime));

        return annualSummaryResDTOList;
    }


    @Override
    public AnnualSummaryCountResDTO getAnnualSummaryCount(List<AnnualSummaryResDTO> excelData) {
        AnnualSummaryCountResDTO annualSummaryCountResDTO = new AnnualSummaryCountResDTO();
        annualSummaryCountResDTO.setTaskNum(excelData.size());
        // 统计总时长
        annualSummaryCountResDTO.setTaskCount(excelData.stream().mapToDouble(AnnualSummaryResDTO::getSumCount).sum());
        // 统计进行中任务数
        annualSummaryCountResDTO.setCompletedTasks(Math.toIntExact(excelData.stream().filter(vo -> vo.getPlanStatus() == 1).count()));
        annualSummaryCountResDTO.setCompletedTasksCount(excelData.stream().filter(vo -> vo.getPlanStatus() == 1).mapToDouble(AnnualSummaryResDTO::getSumCount).sum());
        // 统计完成任务数
        annualSummaryCountResDTO.setOngoingTasks(Math.toIntExact(excelData.stream().filter(vo -> vo.getPlanStatus() == 2).count()));
        annualSummaryCountResDTO.setOngoingTasksCount(excelData.stream().filter(vo -> vo.getPlanStatus() == 2).mapToDouble(AnnualSummaryResDTO::getSumCount).sum());
        // 统计未完成任务数
        annualSummaryCountResDTO.setAbandonedTasks(Math.toIntExact(excelData.stream().filter(vo -> vo.getPlanStatus() == 3).count()));
        annualSummaryCountResDTO.setAbandonedTasksCount(excelData.stream().filter(vo -> vo.getPlanStatus() == 3).mapToDouble(AnnualSummaryResDTO::getSumCount).sum());
        if (annualSummaryCountResDTO.getTaskNum() > 0) {
            DecimalFormat df = new DecimalFormat("#.00");
            // 优秀任务比率
            Double excellentTask = 0D;
            excellentTask = Double.valueOf(excelData.stream().filter(vo -> PlanAchievementEnum.EXCELLENT.getValue().equals(vo.getResult())).count());
            annualSummaryCountResDTO.setExcellentReat(df.format(excellentTask * 100 / annualSummaryCountResDTO.getTaskNum()) + "%");
            // 完成任务比率
            Double completedTask = 0D;
            completedTask = Double.valueOf(excelData.stream().filter(vo -> PlanAchievementEnum.FINISH.getValue().equals(vo.getResult())).count());
            // double 保留两位小数
            annualSummaryCountResDTO.setFinishReat(df.format(completedTask * 100 / annualSummaryCountResDTO.getTaskNum()) + "%");
            // 合格任务比率
            Double qualifiedTask = 0D;
            qualifiedTask = Double.valueOf(excelData.stream().filter(vo -> PlanAchievementEnum.QUAIIFIED.getValue().equals(vo.getResult())).count());
            annualSummaryCountResDTO.setQualifiedReat(df.format(qualifiedTask * 100 / annualSummaryCountResDTO.getTaskNum()) + "%");
            // 失败任务比率
            Double failedTask = 0D;
            failedTask = Double.valueOf(excelData.stream().filter(vo -> PlanAchievementEnum.FAILD.getValue().equals(vo.getResult())).count());
            annualSummaryCountResDTO.setFailReat(df.format(failedTask * 100 / annualSummaryCountResDTO.getTaskNum()) + "%");
            // 无计划比率
            Double noPlanTask = 0D;
            noPlanTask = Double.valueOf(excelData.stream().filter(vo -> PlanAchievementEnum.NO_PLAN.getValue().equals(vo.getResult())).count());
            annualSummaryCountResDTO.setNoPlanReat(df.format(noPlanTask * 100 / annualSummaryCountResDTO.getTaskNum()) + "%");
        }

        return annualSummaryCountResDTO;
    }

    /**
     * 生成年度总结数据
     *
     * @param scheduleLogsList
     * @return
     */
    private List<AnnualSummaryResDTO> generateAnnualSummary(List<ScheduleLogs> scheduleLogsList,AnnualSummaryReqDTO reqDTO) {
        List<AnnualSummaryResDTO> annualSummaryResDTOList = new LinkedList<>();
        for (ScheduleLogs scheduleLogs : scheduleLogsList) {
            AnnualSummaryResDTO annualSummaryResDTO = new AnnualSummaryResDTO();
            String content = scheduleLogs.getModel() + "-" + scheduleLogs.getContent();
            if (StrUtil.isNotBlank(scheduleLogs.getContentDetail())) {
                content += "-" + scheduleLogs.getContentDetail();
            }
            annualSummaryResDTO.setContent(content);
            annualSummaryResDTO.setPlanStatus(scheduleLogs.getPlanStatus());
            annualSummaryResDTO.setPlanStatusStr(ConstGroupConstant.getConstGroupValue("constgroup_plan_status", scheduleLogs.getPlanStatus()));
            annualSummaryResDTO.setPlanTypeStr(ConstGroupConstant.getConstGroupValue("constgroup_plan_type", scheduleLogs.getPlanType()));
            annualSummaryResDTO.setCreateTime(DateUtil.format(scheduleLogs.getCreateTime(), "yyyy-MM-dd"));

            // 计划次数
            Integer planCounts = 0;
            // 获取周期配置
            SchedulePlanLogs schedulePlanLogs = schedulePlanLogsService.getOne(Wrappers.lambdaQuery(SchedulePlanLogs.class).eq(SchedulePlanLogs::getScheduleId, scheduleLogs.getId()));
            if (schedulePlanLogs != null) {
                planCounts = schedulePlanLogs.getPlanCounts();

            }
            annualSummaryResDTO.setPlanClockInNo(planCounts);
            // 获取打卡记录
            List<Clocklogs> clocklogs = clocklogsService.list(Wrappers.lambdaQuery(Clocklogs.class)
                    .eq(Clocklogs::getScheduleId, scheduleLogs.getId())
                    .between(Clocklogs::getClockTime,reqDTO.getStartTime(),reqDTO.getEndTime())
                    .orderBy(true, true, Clocklogs::getClockTime));
            if (clocklogs == null || clocklogs.size() == 0) {
                annualSummaryResDTO.setClockInNo(0);
                annualSummaryResDTO.setSumCount(0D);
                annualSummaryResDTO.setSumCountStr("0 h");

                // 临时计划可以没有打卡记录和完成比
                if (scheduleLogs.getPlanType() == 1) {
                    annualSummaryResDTO.setPercentComplete("-");
                    annualSummaryResDTO.setResult(PlanAchievementEnum.NO_PLAN.getValue());
                } else if (schedulePlanLogs != null) {
                    annualSummaryResDTO.setPercentComplete("0%");
                    annualSummaryResDTO.setResult(PlanAchievementEnum.FAILD.getValue());
                }

            } else {
                annualSummaryResDTO.setClockInNo(clocklogs.size());
                annualSummaryResDTO.setSumCount(clocklogs.stream().mapToDouble(Clocklogs::getUseageHour).sum());
                annualSummaryResDTO.setSumCountStr(String.valueOf(clocklogs.stream().mapToDouble(Clocklogs::getUseageHour).sum()) + " h");
                Integer percentComplete = 0;

                if (planCounts == 0) {
                    annualSummaryResDTO.setPercentComplete("-");
                    annualSummaryResDTO.setResult(PlanAchievementEnum.NO_PLAN.getValue());
                } else if (clocklogs.size() != 0) {
                    // 计算完成比 和 结果
                    percentComplete = clocklogs.size() * 100 / planCounts;
                    annualSummaryResDTO.setPercentComplete(percentComplete + "%");
                    annualSummaryResDTO.setResult(getPercentCompleteResult(percentComplete));

                } else {
                    log.error("不存在的情况出现了！！planCounts{},percentComplete", planCounts, percentComplete);
                }
            }

            annualSummaryResDTOList.add(annualSummaryResDTO);

        }
        return annualSummaryResDTOList;
    }

    /**
     * 获取完成比结果
     *
     * @param percentComplete
     * @return
     */
    private String getPercentCompleteResult(Integer percentComplete) {

        // todo 后续这个比例会放到字典表配置中
        if (percentComplete >= 80) {
            return PlanAchievementEnum.EXCELLENT.getValue();
        } else if (percentComplete >= 60) {
            return PlanAchievementEnum.FINISH.getValue();
        } else if (percentComplete >= 40) {
            return PlanAchievementEnum.QUAIIFIED.getValue();
        } else {
            return PlanAchievementEnum.FAILD.getValue();
        }
    }

    /**
     * 生成周总结 数据
     *
     * @param scheduleLogsList
     * @return
     */
    private List<WeeklySummaryResDTO> generateWeeklySummary(List<SummaryReportResDTO> scheduleLogsList,WeeklySummaryReqDTO reqDTO) {
        List<WeeklySummaryResDTO> weeklySummaryResDTOList = new LinkedList<>();
        for (SummaryReportResDTO scheduleLogs : scheduleLogsList) {
            WeeklySummaryResDTO weeklySummaryResDTO = new WeeklySummaryResDTO();
            String content = scheduleLogs.getModel() + "-" + scheduleLogs.getContent();
            if (StrUtil.isNotBlank(scheduleLogs.getContentDetail())) {
                content += "-" + scheduleLogs.getContentDetail();
            }
            weeklySummaryResDTO.setContent(content);
            weeklySummaryResDTO.setPlanStatus(scheduleLogs.getPlanStatus());
            weeklySummaryResDTO.setPlanStatusStr(ConstGroupConstant.getConstGroupValue("constgroup_plan_status", scheduleLogs.getPlanStatus()));
            weeklySummaryResDTO.setPlanStartTime(scheduleLogs.getPlanStartTime());
            weeklySummaryResDTO.setPlanEndTime(scheduleLogs.getPlanEndTime());
            // 获取打卡记录
            List<Clocklogs> clocklogs = clocklogsService.list(Wrappers.lambdaQuery(Clocklogs.class)
                    .eq(Clocklogs::getScheduleId, scheduleLogs.getId())
                    .between(Clocklogs::getClockTime,reqDTO.getStartTime(),reqDTO.getEndTime())
                    .orderBy(true, true, Clocklogs::getClockTime));
            if (clocklogs == null || clocklogs.size() == 0) {
                weeklySummaryResDTO.setSumCount("0 h");
            } else {
                weeklySummaryResDTO.setSumCount(String.valueOf(clocklogs.stream().mapToDouble(Clocklogs::getUseageHour).sum()) + " h");
                weeklySummaryResDTO.setStartTime(DateUtil.format(clocklogs.get(0).getClockTime(), "yyyy-MM-dd"));
                // 进行中的不填结束时间
                if (weeklySummaryResDTO.getPlanStatus() != 1) {
                    weeklySummaryResDTO.setEndTime(DateUtil.format(clocklogs.get(clocklogs.size() - 1).getClockTime(), "yyyy-MM-dd"));
                }
                String clockInDetail = "";
                // 填写打卡详情对象
                List<ClockInDetail> clockInDetails = new LinkedList<>();
                for (Clocklogs clocklog : clocklogs) {
                    ClockInDetail detail = new ClockInDetail();
                    detail.setClockInTime(DateUtil.format(clocklog.getClockTime(), "yyyy-MM-dd"));
                    detail.setHour(String.valueOf(clocklog.getUseageHour()) + " h");
                    detail.setRemark(clocklog.getRemark());
                    clockInDetails.add(detail);

                    clockInDetail += detail.getClockInTime() + "-" + detail.getHour();
                    if (detail.getRemark() != null) {
                        clockInDetail += "-" + detail.getRemark() + ";\r\n";
                    } else {
                        clockInDetail += ";\r\n";
                    }
                }
                weeklySummaryResDTO.setClockInDetails(clockInDetails);
                weeklySummaryResDTO.setClockInDetail(clockInDetail);
            }

            weeklySummaryResDTOList.add(weeklySummaryResDTO);
        }
        return weeklySummaryResDTOList;
    }


    /**
     * 添加打卡数据
     *
     * @param summaryReportResDTOList
     * @return
     */
    private List<SummaryReportResDTO> queryClockIn(List<SummaryReportResDTO> summaryReportResDTOList,SummaryReportReqDTO reqDTO) {
        for (SummaryReportResDTO resDTO : summaryReportResDTOList) {
            // 根据scheduleId 查询所有的打卡记录
            String scheduleId = resDTO.getId();
            List<Clocklogs> clocklogs = clocklogsService.list(Wrappers.lambdaQuery(Clocklogs.class)
                    .eq(Clocklogs::getScheduleId, scheduleId)
                    .between(Clocklogs::getClockTime,reqDTO.getStartTime(),reqDTO.getEndTime())
                    .orderBy(true, true, Clocklogs::getClockTime));
            if (clocklogs == null || clocklogs.size() == 0) {
                continue;
            }
            double sumCount = clocklogs.stream().mapToDouble(Clocklogs::getUseageHour).sum();
            resDTO.setSumCount((int) sumCount);
            resDTO.setStartTime(DateUtil.format(clocklogs.get(0).getClockTime(), "yyyy-MM-dd"));
            // 进行中的不填结束时间
            if (resDTO.getPlanStatus() != 1) {
                resDTO.setEndTime(DateUtil.format(clocklogs.get(clocklogs.size() - 1).getClockTime(), "yyyy-MM-dd"));
            }
        }
        return summaryReportResDTOList;
    }
}
